package com.handler.http.message.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.handler.http.message.annotations.IgnoreDecrypt;
import com.handler.http.message.enums.RequestEnum;
import com.handler.http.message.verify.VerifyRequestData;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.rmi.ServerException;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author guoQ.z
 * @date 2020/12/29 18:01
 * 对请求数据进行  解密
 */
@Slf4j
//@ControllerAdvice(basePackages = "com.handler.http.message.controller")
@RestControllerAdvice
public class DecryptRequestBodyAdvice implements RequestBodyAdvice {

    /**
     * 返回true 向下进行，
     *
     * @param methodParameter 方法的参数
     * @param type
     * @param aClass
     * @return
     */
    @Override
    public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        System.out.println("DecryptRequestBodyAdvice :  into ....");
        //判断是否有此注解,只有为true时才会执行afterBodyRead
        if (methodParameter.getParameterAnnotation(RequestBody.class) != null) {
            return !Objects.requireNonNull(methodParameter.getMethod()).isAnnotationPresent(IgnoreDecrypt.class);
        }
        return false;
    }

    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
//        如果有头信息 的逻辑过滤判断
        HttpHeaders headers = httpInputMessage.getHeaders();
        List<String> shscs = headers.get("shsc");
        if (CollectionUtils.isNotEmpty(shscs) && "shsc".equals(shscs.get(0))) {
            return httpInputMessage;
        }

        if (null != methodParameter.getParameterAnnotation(RequestBody.class)) {
            if (!Objects.requireNonNull(methodParameter.getMethod()).isAnnotationPresent(IgnoreDecrypt.class)) {
                try {
                    String requestBody = new BufferedReader(new InputStreamReader(httpInputMessage.getBody())).lines()
                            .collect(Collectors.joining(System.lineSeparator()));
                    log.info("接收到请求数据:{}", requestBody);
                    JSONObject jsonObject = JSON.parseObject(requestBody);

                    // 消息体
                    String body = jsonObject.getString(RequestEnum.body.name());
                    VerifyRequestData.verifyBody(body);

                    // 版本号
                    String version = jsonObject.getString(RequestEnum.version.name());
                    VerifyRequestData.verifyVersion(version);

                    // 时间
                    String timestamp = jsonObject.getString(RequestEnum.timestamp.name());
                    VerifyRequestData.verifyTimestamp(timestamp);

                    // 解签消息体
                    String decryptBody = VerifyRequestData.decryptBody(body);

                    return new DecryptHttpInputMessage(httpInputMessage, decryptBody);
                } catch (Exception ex) {
                    log.info("接收到请求，错误信息：{}", ex.getMessage());
                    throw new ServerException(ex.getMessage());
                }
            }
        }

        return httpInputMessage;
    }

    @Override
    public Object afterBodyRead(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return body;
    }

    @Override
    public Object handleEmptyBody(Object body, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
        return body;
    }
}
